using System;
using System.Collections.Generic;
using Engine;
using Engine.Graphics;
using Game;

namespace RuthlessConquest {
    public class PlayersModule : Module {
        public const int MaxFactions = 6;
        public const int MaxPlayers = 6;
        public const string fName = "RCPlayersModule";

        public DynamicArray<Player> publicPlayers = new();

        public DynamicArray<Player> publicSpectators = new();

        //public DynamicArray<Player> TmpPlayersList = new();
        public FactionStatus[] FactionStatuses = new FactionStatus[6];
        public double[] FactionStatusChangeTimes = new double[6];
        public bool[] TmpHasAnything = new bool[6];
        public Dictionary<Guid, string> PlayerAddresses = new();
        public Dictionary<Guid, string> PlayerLocations = new();

        public bool IsGameFinished { get; set; }
        public HumanPlayer ControllingPlayer { get; set; }
        public ReadOnlyList<Player> Players => new(publicPlayers);
        public ReadOnlyList<Player> Spectators => new(publicSpectators);

        public PlayersModule(Game game) : base(game) {
            /*game.EntityAdded += delegate(Entity e) {
                Player player = e as Player;
                if (player != null) {
                    if (player.Faction == Faction.Neutral) {
                        throw new InvalidOperationException();
                    }
                    if (player.Faction == Faction.None) {
                        publicSpectators.Add(player);
                        publicSpectators = new DynamicArray<Player>(publicSpectators.OrderBy(p => p.Guid.ToString()));
                    }
                    else {
                        if (publicPlayers.Any(p => p.Faction == player.Faction)) {
                            throw new InvalidOperationException();
                        }
                        publicPlayers.Add(player);
                        publicPlayers = new DynamicArray<Player>(publicPlayers.OrderBy(p => p.Guid.ToString()));
                    }
                    if (player.Guid == SettingsManager.PlayerGuid) {
                        ControllingPlayer = (HumanPlayer)player;
                    }
                }
            };
            game.EntityRemoved += delegate(Entity e) {
                if (e is Player player2) {
                    publicPlayers.Remove(player2);
                    publicSpectators.Remove(player2);
                    if (player2 == ControllingPlayer) {
                        ControllingPlayer = null;
                    }
                }
            };*/
        }

        public Player FindPlayer(Faction faction) {
            foreach (Player player in Players) {
                if (player.Faction == faction) {
                    return player;
                }
            }
            return null;
        }

        public FactionStatus GetFactionStatus(Faction faction) {
            if (faction < Faction.Faction1
                || faction >= Faction.Neutral) {
                return FactionStatus.Undecided;
            }
            return FactionStatuses[(int)faction];
        }

        public double GetFactionStatusChangeTime(Faction faction) {
            if (faction < Faction.Faction1
                || faction >= Faction.Neutral) {
                return 0.0;
            }
            return FactionStatusChangeTimes[(int)faction];
        }

        public void Update() {
            foreach (Player player in Players) {
                player.Update();
            }
            int num = 0;
            if (ControllingPlayer != null) {
                Game.Screen.PlayerLabels[num++].Player = ControllingPlayer;
            }
            foreach (Player player2 in Players) {
                if (num < Game.Screen.PlayerLabels.Count
                    && player2 != ControllingPlayer
                    && (player2.Status >= FactionStatus.Undecided || player2 is HumanPlayer)) {
                    Game.Screen.PlayerLabels[num++].Player = player2;
                }
            }
            while (num < Game.Screen.PlayerLabels.Count) {
                Game.Screen.PlayerLabels[num++].Player = null;
            }
        }

        public void Draw(Color colorTransform) {
            foreach (Player player in Players) {
                player.Draw(colorTransform);
            }
            CameraModule.PrimitivesRenderer.Flush(CameraModule.WorldToScreenMatrix * PrimitivesRenderer2D.ViewportMatrix());
        }

        public void Step() {
            foreach (Player player in Players) {
                player.Step();
            }
            UpdateFactionStatuses();
        }

        public void UpdateFactionStatuses() {
            PlanetsModule planetsModule = Game.PlanetsModule;
            ShipsModule shipsModule = Game.ShipsModule;
            for (int i = 0; i < 6; i++) {
                if (FactionStatuses[i] != FactionStatus.Undecided) {
                    continue;
                }
                bool flag = false;
                HashSet<Planet> planets = planetsModule.FactionOwnPlanets[i];
                if (planets.Count > 0) {
                    flag = true;
                }
                if (!flag) {
                    if (shipsModule.FactionOwnShips[i] > 0) {
                        flag = true;
                    }
                    if (!flag) {
                        FactionStatuses[i] = FactionStatus.LostEliminated;
                        FactionStatusChangeTimes[i] = Time.FrameStartTime;
                        Player player = FindPlayer((Faction)i);
                        if (player != null) {
                            Game.Screen.MessagesListWidget.AddMessage(
                                string.Format(LanguageControl.Get(fName, "2"), player.Name),
                                Player.GetColor(player.Faction),
                                true
                            );
                        }
                    }
                }
                TmpHasAnything[i] = flag;
            }
            /*foreach (Planet planet in PlanetsModule.Planets) {
                if (planet.Faction >= Faction.Faction1
                    && planet.Faction < Faction.Neutral) {
                    TmpHasAnything[(int)planet.Faction] = true;
                }
            }
            foreach (Ship ship in ShipsModule.Ships) {
                if (ship.Faction >= Faction.Faction1
                    && ship.Faction < Faction.Neutral) {
                    TmpHasAnything[(int)ship.Faction] = true;
                }
            }*/
            Faction? ownAllSpecialPlanetFaction = null;
            /*for (int j = 0; j < 6; j++) {
                bool flag = true;
                foreach (Planet planet2 in PlanetsModule.Planets) {
                    if (planet2.IsSpecial
                        && planet2.Faction != (Faction)j) {
                        flag = false;
                        break;
                    }
                }
                if (flag) {
                    ownAllSpecialPlanetFaction = (Faction)j;
                    break;
                }
            }*/
            foreach (Planet planet in planetsModule.SpecialPlanets) {
                if (ownAllSpecialPlanetFaction.HasValue) {
                    if (ownAllSpecialPlanetFaction.Value != planet.Faction) {
                        ownAllSpecialPlanetFaction = null;
                        break;
                    }
                }
                else {
                    ownAllSpecialPlanetFaction = planet.Faction;
                }
            }
            /*Faction? onlyHasAnythingFaction = null;
            for (int k = 0; k < 6; k++) {
                if (!TmpHasAnything[k]) {
                    continue;
                }
                bool flag2 = true;
                for (int l = 0; l < 6; l++) {
                    if (l != k
                        && TmpHasAnything[l]) {
                        flag2 = false;
                        break;
                    }
                }
                if (flag2) {
                    onlyHasAnythingFaction = (Faction)k;
                    break;
                }
            }*/
            int hasAnythingFactionsCount = 0;
            int lastHasAnythingFaction = -1;
            for (int k = 0; k < 6; k++) {
                if (TmpHasAnything[k]) {
                    if (hasAnythingFactionsCount++ > 0) {
                        break;
                    }
                    lastHasAnythingFaction = k;
                }
            }
            Faction? onlyHasAnythingFaction = hasAnythingFactionsCount == 1 ? (Faction?)lastHasAnythingFaction : null;
            /*IsGameFinished = true;
            for (int m = 0; m < 6; m++) {
                if (FactionStatuses[m] != 0) {
                    continue;
                }
                if (!TmpHasAnything[m]) {
                    FactionStatuses[m] = FactionStatus.LostEliminated;
                    FactionStatusChangeTimes[m] = Time.FrameStartTime;
                }
                else
                if (ownAllSpecialPlanetFaction.HasValue
                    && ownAllSpecialPlanetFaction != (Faction?)m) {
                    FactionStatuses[m] = FactionStatus.Lost;
                    FactionStatusChangeTimes[m] = Time.FrameStartTime;
                }
                else if (onlyHasAnythingFaction == (Faction?)m) {
                    FactionStatuses[m] = FactionStatus.WonEliminatedOthers;
                    FactionStatusChangeTimes[m] = Time.FrameStartTime;
                }
                else if (ownAllSpecialPlanetFaction == (Faction?)m) {
                    FactionStatuses[m] = FactionStatus.Won;
                    FactionStatusChangeTimes[m] = Time.FrameStartTime;
                }
                if (FactionStatuses[m] > FactionStatus.Undecided) {
                    Player player = FindPlayer((Faction)m);
                    if (player != null) {
                        Game.Screen.MessagesListWidget.AddMessage(player.Name + " is victorious!", Player.GetColor(player.Faction), true);
                    }
                }
                else if (FactionStatuses[m] < FactionStatus.Undecided) {
                    Player player2 = FindPlayer((Faction)m);
                    if (player2 != null) {
                        Game.Screen.MessagesListWidget.AddMessage(player2.Name + " defeated!", Player.GetColor(player2.Faction), true);
                    }
                }
            }*/
            if (ownAllSpecialPlanetFaction.HasValue
                && ownAllSpecialPlanetFaction != Faction.Neutral) {
                IsGameFinished = true;
                for (int m = 0; m < 6; m++) {
                    if (FactionStatuses[m] != 0) {
                        continue;
                    }
                    if (m == (int)ownAllSpecialPlanetFaction.Value) {
                        FactionStatuses[m] = FactionStatus.Won;
                        FactionStatusChangeTimes[m] = Time.FrameStartTime;
                        Player player = FindPlayer((Faction)m);
                        if (player != null) {
                            Game.Screen.MessagesListWidget.AddMessage(
                                string.Format(LanguageControl.Get(fName, "1"), player.Name),
                                Player.GetColor(player.Faction),
                                true
                            );
                        }
                    }
                    else {
                        FactionStatuses[m] = FactionStatus.Lost;
                        FactionStatusChangeTimes[m] = Time.FrameStartTime;
                        Player player2 = FindPlayer((Faction)m);
                        if (player2 != null) {
                            Game.Screen.MessagesListWidget.AddMessage(
                                string.Format(LanguageControl.Get(fName, "2"), player2.Name),
                                Player.GetColor(player2.Faction),
                                true
                            );
                        }
                    }
                }
                return;
            }
            if (onlyHasAnythingFaction.HasValue) {
                IsGameFinished = true;
                FactionStatuses[(int)onlyHasAnythingFaction.Value] = FactionStatus.WonEliminatedOthers;
                Player player = FindPlayer(onlyHasAnythingFaction.Value);
                if (player != null) {
                    Game.Screen.MessagesListWidget.AddMessage(
                        string.Format(LanguageControl.Get(fName, "1"), player.Name),
                        Player.GetColor(player.Faction),
                        true
                    );
                }
            }
        }
    }
}